Skip to main content
List and Map patterns are structural patterns that match values against the structure of List and Map types, respectively. They enable the simultaneous validation of a collection’s shape (length or key existence) and the destructuring of its elements into variables.

List Pattern

A list pattern matches an object if:
  1. The object implements the List interface.
  2. The object’s length matches the number of subpatterns (unless a rest element is used).
  3. Each element in the list matches the corresponding subpattern at that position.

Syntax

The pattern is enclosed in square brackets [] and relies on positional matching.
// Basic syntax structure
// [subpattern1, subpattern2, ...]

Exact Length Matching

When no rest element is present, the pattern enforces a strict length check.
const list = [10, 20];

// Matches because length is 2 and elements match variable patterns
// Destructures 10 into 'a' and 20 into 'b'
var [a, b] = list; 

// Runtime error in irrefutable context (declaration)
// or non-match in refutable context (switch/if-case)
// because list length (2) does not equal pattern length (3)
// var [x, y, z] = list; 

Rest Element

The rest element (...) allows matching lists of arbitrary lengths. It matches any number of elements at its position.
  • Unnamed Rest: ... ignores the remaining elements.
  • Named Rest: ...variableName captures the remaining elements into a new List.
var list = [1, 2, 3, 4, 5];

// Matches the first element, ignores the rest
var [first, ...] = list; 

// Matches the first and last elements, ignores the middle
var [head, ..., tail] = list;

// Captures the middle elements into a new list 'others'
// a = 1, others = [2, 3, 4], b = 5
var [a, ...others, b] = list;

Map Pattern

A map pattern matches an object if:
  1. The object implements the Map interface.
  2. The map contains all keys specified in the pattern.
  3. The values associated with those keys match their corresponding subpatterns.
Unlike list patterns, map patterns do not require matching all elements within the map. The match succeeds as long as the explicitly requested keys exist.

Syntax

The pattern is enclosed in curly braces {}. It relies on key-based matching. Keys must be constant expressions (literals or const variables).
// Basic syntax structure using string literals as keys
// {'key': subpattern, 'key2': subpattern2}

Key Matching and Destructuring

Map patterns require explicit keys mapping to subpatterns. There is no shorthand syntax (variable punning) for map patterns; the key must always be defined explicitly, even if the variable name matches the key.
var map = {'name': 'Alice', 'age': 30, 'active': true};

// Matches if 'name' and 'age' keys exist.
// Destructures value of 'name' into variable 'n'.
// Destructures value of 'age' into variable 'a'.
// The 'active' key is ignored.
var {'name': n, 'age': a} = map;

// To destructure into variables with the same names as the keys,
// you must still state the key explicitly.
var {'name': name, 'age': age} = map;

Recursive Composition

List and Map patterns are composable. A subpattern within a list or map pattern can be another list or map pattern, allowing for deep destructuring of nested data structures.
var data = {
  'user': 'Admin',
  'roles': ['read', 'write', 'delete']
};

// Outer pattern: Map Pattern
// Inner pattern: List Pattern (matching the 'roles' value)
var {
  'user': username,
  'roles': [primaryRole, ...secondaryRoles]
} = data;

// Result:
// username = 'Admin'
// primaryRole = 'read'
// secondaryRoles = ['write', 'delete']

Type Annotation in Patterns

Type annotations can be applied to the pattern itself or individual subpatterns to enforce type checks during matching.
dynamic data = [1, 2];

// Enforces that 'data' is a List<int>
var <int>[x, y] = data;

dynamic mapData = {'id': 'A100'};

// Enforces that the value of 'id' is a String
var {'id': String id} = mapData;
Master Dart with Deep Grasping Methodology!Learn More